home *** CD-ROM | disk | FTP | other *** search
- Newsgroups: comp.sources.misc
- subject: v08i002: A C execution profiler for MS-DOS
- From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
- Reply-To: diomidis@ecrcvax.UUCP ("Diomidis Spinellis")
-
- Posting-number: Volume 8, Issue 2
- Submitted-by: diomidis@ecrcvax.UUCP ("Diomidis Spinellis")
- Archive-name: prof.msc
-
- [...so how about a Turbo C version? ++bsa]
-
- #! /bin/sh
- # This is a shell archive, meaning:
- # 1. Remove everything above the #! /bin/sh line.
- # 2. Save the resulting text in a file.
- # 3. Execute the file with /bin/sh (not csh) to create the files:
- # README
- # Makefile
- # prof.c
- # profprt.c
- # test.c
- # This archive created: Mon Aug 14 16:46:48 1989
- export PATH; PATH=/bin:$PATH
- if test -f 'README'
- then
- echo shar: will not over-write existing file "'README'"
- else
- sed 's/^X//' << \SHAR_EOF > 'README'
- XIncluded here is the source for an execution profiling system that can
- Xbe used with the Microsoft C or the Microsoft Quick C compiler. It
- Xgives the time percentage a program spends in different functions. It
- Xis an indispensable tool when trying to optimise a program. The system
- Xhas been tested with Microsoft C Version 5.00.
- X
- XIn order to use the profiler first create the object files sprof.obj,
- Xlprof.obj, mprof.obj and cprof.obj by typing ``make''. The makefile
- Xsupplied expects a Un*x compatible linker, so if you are using the one
- Xthat came with the compiler do the compilations by hand.
- X
- XCompile your program in such a way as to create a linker map file. To
- Xdo this link your program with the -Fm option of cl or the /MAP option
- Xof the linker. The appropriate [slmc]prof.obj module has to be linked
- Xtogether with the rest of the program. The first letter of the module
- Xindicates the memory model in use. The program should call the
- Xfunction prof_start( argv[0] ) for versions of MS-DOS above or equal to
- X3.00 or prof_start( .map file name ) for MS-DOS versions before 3.00 in
- Xorder to start profiling. When the program finishes the profiler
- Xautomatically produces a prof.out file that contains the names of all
- Xpublic symbols and the number of hits for each one.
- X
- XYou can read the results directly from the prof.out file, or you can
- Xsummarize them using profprt. Profprt reads the prof.out file (or
- Xanother file if specified) and produces a list of hits and percentages
- Xfor the functions for which hits were recorded. If given a -h option it
- Xalso produces a histogram of the relative timings.
- X
- XA small test program is included to check the profiler functioning. It
- Xgenerally found the profiler results to be within 1% of the expected
- Xresults on an 8MHz PC.
- X
- XThe profiler is all written in C utilizing the ability to create
- Xinterrupt handlers in C. It finds the addresses of the functions from
- Xthe linker map file. It should not be very hard to modify the source
- Xfor other compilers. Keep in mind that functions declared as static
- Xare not included in the map file, thus will not be profiled and plan
- Xaccordingly. One solution is to compile with -Dstatic= if the naming
- Xscheme used allows it. Pay attention to quantization errors and to
- Xerrors due to incorrectly specified boundaries. Portions of the code
- Xthat are executed with interrupts disabled will not be profiled.
- X
- XDiomidis D. Spinellis (dds@cc.ic.ac.uk)
- XMyrsinis 1
- XGR-145 62 Kifisia
- XGREECE
- SHAR_EOF
- if test 2465 -ne "`wc -c < 'README'`"
- then
- echo shar: error transmitting "'README'" '(should have been 2465 characters)'
- fi
- fi # end of overwriting check
- if test -f 'Makefile'
- then
- echo shar: will not over-write existing file "'Makefile'"
- else
- sed 's/^X//' << \SHAR_EOF > 'Makefile'
- X#
- X# Makefile for the profiler
- X#
- X# (C) Copyright 1988, 1989 Diomidis D. Spinellis. All rights reserved.
- X# See the file profprt.c for distribution details.
- X#
- X# You need a Uni*x compatible make program to use this makefile.
- X# Microsoft make will probably not work.
- X
- X# Debugging flags
- X#CFLAGS=-Od -W3 -qc -Zi -DDEBUG
- X# Production flags
- XCFLAGS=-Ox -W3
- X
- XCC=cl
- X#CC=qcl
- X
- Xall: lprof.obj mprof.obj cprof.obj sprof.obj profprt.exe
- X
- Xtest.exe: test.obj sprof.obj
- X $(CC) -Fm $(CFLAGS) test.obj sprof.obj
- X
- Xlprof.obj: prof.c
- X $(CC) -AL $(CFLAGS) -c -Folprof.obj prof.c
- X
- Xcprof.obj: prof.c
- X $(CC) -AC $(CFLAGS) -c -Focprof.obj prof.c
- X
- Xmprof.obj: prof.c
- X $(CC) -AM $(CFLAGS) -c -Fomprof.obj prof.c
- X
- Xsprof.obj: prof.c
- X $(CC) -AS $(CFLAGS) -c -Fosprof.obj prof.c
- X
- Xtest.obj: test.c
- X $(CC) -AS -c test.c
- X
- Xprofprt.exe: profprt.c
- X $(CC) $(CFLAGS) profprt.c
- X
- Xtest: test.exe
- X test
- X
- Xinstall:
- X copy lprof.obj $$LIB
- X copy cprof.obj $$LIB
- X copy mprof.obj $$LIB
- X copy sprof.obj $$LIB
- X
- Xclean:
- X rm -f *.exe *.obj *.map prof.out
- X
- Xshar:
- X shar -pX -c README Makefile prof.c profprt.c test.c >prof.shar
- SHAR_EOF
- if test 1066 -ne "`wc -c < 'Makefile'`"
- then
- echo shar: error transmitting "'Makefile'" '(should have been 1066 characters)'
- fi
- fi # end of overwriting check
- if test -f 'prof.c'
- then
- echo shar: will not over-write existing file "'prof.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'prof.c'
- X/*
- X * A C program profiler.
- X *
- X * (C) Copyright 1988, 1989 Diomidis D. Spinellis. All rights reserved.
- X *
- X * Redistribution and use in source and binary forms are permitted
- X * provided that the above copyright notice and this paragraph are
- X * duplicated in all such forms and that any documentation,
- X * advertising materials, and other materials related to such
- X * distribution and use acknowledge that the software was developed
- X * by Diomidis Spinellis.
- X *
- X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- X *
- X * Author: Diomidis D. Spinellis (dds@cc.ic.ac.uk)
- X * Myrsinis 1
- X * GR-145 62 Kifisia
- X * GREECE
- X *
- X * $Header: PROF.C^v 1.1 88/11/20 17:33:16 dds Rel $
- X *
- X * $Log: PROF.C^v $
- X * Revision 1.1 88/11/20 17:33:16 dds
- X * Initial revision
- X *
- X */
- X
- X#include <stddef.h>
- X#include <stdlib.h>
- X#include <stdio.h>
- X#include <string.h>
- X#include <dos.h>
- X
- X/* Linker output maximum line length */
- X#define LINELEN 129
- X/* Linker output maximum symbol length */
- X#define STRLEN 65
- X
- X/* Entries can be absolute or relocatable */
- Xenum relocation { absolute, relocatable };
- X
- X/* Function prototypes */
- Xstatic void add_proc(char * name, unsigned long addr, enum relocation rel);
- Xstatic void adjust_proc(long main_offset);
- Xstatic void install_int(void);
- Xstatic int prof_end(void);
- Xstatic void * xmalloc(size_t size);
- Xstatic void * xrealloc(void * buffer, size_t size);
- Xstatic char * strsave(char * string);
- Xstatic void interrupt far timer_handler(int es,int ds,int di,int si,int bp,
- X int sp,int bx,int dx,int cx,int ax,int ip,int cs,int flags);
- Xvoid main(int argc, char *argv[]);
- X#ifdef DEBUG
- Xstatic void dump_table(void);
- Xstatic void test_search(void);
- Xstatic void disp(long n);
- X#endif
- X
- Xstatic char rcsid[] = "$Header: PROF.C^v 1.1 88/11/20 17:33:16 dds Rel $";
- X
- Xvoid
- Xprof_start(char * argv0)
- X{
- X FILE *f;
- X static char fname[65];
- X static char line[LINELEN];
- X static char str1[STRLEN], str2[STRLEN], str3[STRLEN], str4[STRLEN],
- X str5[STRLEN];
- X enum {searchsegs, scansegs, searchprocs, scanprocs } state;
- X static char *state_errs[] = {
- X "start of segment definitions",
- X "ENDCODE segment definition",
- X "the ``Publics by Value'' line",
- X "address greater than ENDCODE was found"
- X };
- X unsigned int seg, off;
- X unsigned long endcode;
- X int linenum = 0;
- X unsigned long main_addr, addr;
- X long main_offset = -1;
- X void far * main_p;
- X
- X /* Find the address of main to adjust everything else */
- X main_p = (void far *)main;
- X main_addr = ((unsigned long)FP_SEG(main_p) << 4) +
- X (unsigned long)FP_OFF(main_p);
- X #ifdef DEBUG
- X printf("main=%08lx\n", main_addr);
- X #endif
- X
- X add_proc("DOS", 0l, absolute);
- X strcpy(fname, argv0);
- X strcpy(strrchr(fname, '.'), ".MAP");
- X
- X if ((f = fopen(fname, "r")) == NULL) {
- X perror(fname);
- X exit(1);
- X }
- X
- X state = searchsegs;
- X while (fgets(line, LINELEN, f)) {
- X linenum++;
- X switch (state) {
- X case searchsegs :
- X if (sscanf(line, " %s %s %s %s %s ",
- X str1, str2, str3, str4, str5) == 5 &&
- X strcmp(str1, "Start") == 0 &&
- X strcmp(str2, "Stop") == 0 &&
- X strcmp(str3, "Length") == 0 &&
- X strcmp(str4, "Name") == 0 &&
- X strcmp(str5, "Class") == 0)
- X state = scansegs;
- X break;
- X case scansegs :
- X if (sscanf(line, " %lxH %*lxH %*lxH %*s %s ",
- X &endcode, str1) != 2) {
- X fprintf(stderr,
- X "%s(%d) : Unable to parse line : %s\n",
- X fname, linenum, line);
- X exit(1);
- X }
- X if (strcmp(str1, "ENDCODE") == 0)
- X state = searchprocs;
- X break;
- X case searchprocs :
- X if (sscanf(line, " %s %s %s %s ", str1, str2, str3,
- X str4) == 4 &&
- X strcmp(str1, "Address") == 0 &&
- X strcmp(str2, "Publics") == 0 &&
- X strcmp(str3, "by") == 0 &&
- X strcmp(str4, "Value") == 0)
- X state = scanprocs;
- X break;
- X case scanprocs :
- X if (*line == '\n' || sscanf(line, " %x:%x Abs %s ",
- X &seg, &off, str1) == 3)
- X break;
- X if (sscanf(line, " %x:%x %s ", &seg, &off, str1) != 3) {
- X fprintf(stderr,
- X "%s(%d) : Unable to parse line : %s\n",
- X fname, linenum, line);
- X exit(1);
- X }
- X addr = ((unsigned long)seg << 4) + (unsigned long)off;
- X if (strcmp(str1, "_main") == 0)
- X main_offset = addr;
- X add_proc(str1, addr + main_addr, relocatable);
- X if (addr > endcode) {
- X /*
- X * Add here in ascending order any important
- X * memory bounds. One idea would be to partition
- X * the BIOS in tasks e.g. printer, screen etc.
- X */
- X add_proc("UNKOWN", addr + main_addr + 1,
- X relocatable);
- X add_proc("EGA_BIOS", 0xc0000l, absolute);
- X add_proc("FDISK_BIOS", 0xc8000l, absolute);
- X add_proc("SYSTEM_ROM", 0xf0000l, absolute);
- X add_proc("SYSTEM_BIOS", 0xfe000l, absolute);
- X add_proc("OUTER_SPACE", (unsigned long)-1l,
- X absolute);
- X fclose(f);
- X if (main_offset == -1) {
- X fputs("_main address not found\n",
- X stderr);
- X exit(1);
- X }
- X adjust_proc(main_offset);
- X if (onexit(prof_end) == NULL) {
- X fputs("onexit failed\n", stderr);
- X exit(1);
- X }
- X #ifdef DEBUG
- X dump_table();
- X test_search();
- X #endif
- X install_int();
- X return ;
- X }
- X }
- X }
- X /* Something went wrong */
- X fprintf(stderr, "%s(%d) EOF reached before %s\n", fname, linenum,
- X state_errs[state]);
- X exit(1);
- X}
- X
- X/* The structure where procedures are kept */
- Xstatic struct proc_data {
- X unsigned long addr ; /* Procedure start address */
- X unsigned long count ; /* Hit count set by interrupt */
- X char *name ; /* Procedure name */
- X enum relocation rel ; /* Relocation type */
- X} *procs;
- X
- X/* Number of procedures and allocated memory */
- Xstatic int procnum, procalloc;
- X
- X/* Size of memory allocation chunk */
- X#define BLK 30
- X
- X/* Define a procedure */
- Xstatic void
- Xadd_proc(char * name, unsigned long addr, enum relocation rel)
- X{
- X if (procs == NULL) {
- X procs = xmalloc(sizeof(struct proc_data) * BLK);
- X procalloc = BLK;
- X }
- X procs[procnum].addr = addr;
- X procs[procnum].count = 0l;
- X procs[procnum].name = strsave(name);
- X procs[procnum].rel = rel;
- X procnum++;
- X if (procnum >= procalloc) {
- X procalloc += BLK;
- X procs = xrealloc(procs, sizeof(struct proc_data) *
- X procalloc);
- X }
- X}
- X
- X/*
- X * Adjust downwards the memory allocated for procedure data storage
- X * and subtract main_offset.
- X */
- Xstatic void
- Xadjust_proc(long main_offset)
- X{
- X struct proc_data *pp;
- X
- X xrealloc(procs, sizeof(struct proc_data) * procnum);
- X for (pp = procs ; pp < &procs[procnum] ; pp++)
- X if (pp->rel == relocatable)
- X pp->addr -= main_offset;
- X}
- X
- X/* Timer interrupt (Do not use 0x1c since it is always called from BIOS) */
- X#define TIMER_INT 8
- X
- X/* Old timer handler to chain to */
- Xstatic void (interrupt far * old_timer_handler)(void);
- X
- X/* Disable timer handler and print the profiling results */
- Xstatic int
- Xprof_end(void)
- X{
- X register i;
- X FILE *f;
- X
- X _dos_setvect(TIMER_INT, old_timer_handler);
- X if ((f = fopen("prof.out", "w")) == NULL) {
- X perror("prof.out");
- X return 1;
- X }
- X for (i = 0 ; i < procnum ; i++)
- X fprintf(f, "%s %ld\n", procs[i].name, procs[i].count);
- X fclose(f);
- X return 0;
- X}
- X
- X/* Allocate memory with error checking. */
- Xstatic void *
- Xxmalloc(size_t size)
- X{
- X void * p;
- X
- X if ((p = malloc(size)) == NULL) {
- X fputs("Profiler : Out of memory\n", stderr);
- X exit(1);
- X }
- X return p;
- X}
- X
- X/* Reallocate memory with error checking. */
- Xstatic void *
- Xxrealloc(void * buffer, size_t size)
- X{
- X void * p;
- X
- X
- X if ((p = realloc(buffer, size)) == NULL) {
- X fputs("Profiler : Out of memory\n", stderr);
- X exit(1);
- X }
- X return p;
- X}
- X
- X/* Save a string in allocated memory */
- Xstatic char *
- Xstrsave(char * string)
- X{
- X return strcpy(xmalloc(strlen(string) + 1), string);
- X}
- X
- X/* The timer interrupt handler */
- Xstatic void interrupt far
- Xtimer_handler(es,ds,di,si,bp,sp,bx,dx,cx,ax,ip,cs,flags)
- X{
- X long addr;
- X int lower, upper, middle;
- X
- X addr = ((unsigned long)cs << 4) + (unsigned long)ip;
- X
- X #ifdef DEBUG
- X disp(addr);
- X #endif
- X /*
- X * Precondition :
- X * { a[k] < a[k+1] & 0 <= k <= procnum & a[0] <= addr < a[procnum] }
- X */
- X lower = 0;
- X upper = procnum - 2;
- X /*
- X * Invariant :
- X * { a[l] <= addr < a[u] }
- X * Variant :
- X * { u - l }
- X */
- X while (upper - lower > 1) {
- X middle = (lower + upper) / 2;
- X /*
- X * m = l + (u - l) / 2 = (u + l) / 2
- X * m = l + (u - l) / 2 & u - l > 1 implies l < m < u as:
- X * m = (u + l) / 2 < (u + u) / 2 = u implies m < u
- X * m = l + (u - l) / 2 >= l + 1 implies m > l
- X */
- X if (procs[middle].addr <= addr)
- X lower = middle;
- X else
- X upper = middle;
- X }
- X /*
- X * Postcondition :
- X * { a[f] <= addr < a[f + 1] } which can be expressed as:
- X * { a[l] <= addr < a[u] & u = l + 1 }
- X */
- X procs[lower].count++;
- X (*old_timer_handler)();
- X /* Silence warnings */
- X (void)(es,ds,di,si,bp,sp,bx,dx,cx,ax,ip,cs,flags);
- X}
- X
- X/* Install the interrupt driver */
- Xstatic void
- Xinstall_int(void)
- X{
- X old_timer_handler = _dos_getvect(TIMER_INT);
- X _dos_setvect(TIMER_INT, timer_handler);
- X}
- X
- X#ifdef DEBUG
- X
- X/* Very fast display of a number on the screen. (Define MDA for mono adapter) */
- X
- X#ifdef MDA
- X#define REGEN_BASE 0xb0000000
- X#else /* CGA */
- X#define REGEN_BASE 0xb8000000
- X#endif
- X
- Xstatic void
- Xdisp(long n)
- X{
- X register i;
- X char far * sb = (char far *)(REGEN_BASE + 20);
- X
- X for (i = 0 ; i < 8 ; i++) {
- X *sb = "0123456789abcdef"[n % 16];
- X n /= 16;
- X sb -= 2;
- X }
- X}
- X
- X/* Test the binary search algorithm */
- Xstatic void
- Xpr_name(long addr)
- X{
- X int lower, upper, middle;
- X
- X /*
- X * Precondition :
- X * { a[k] < a[k+1] & 0 <= k <= procnum & a[0] <= addr < a[procnum] }
- X */
- X lower = 0;
- X upper = procnum - 2;
- X /*
- X * Invariant :
- X * { a[l] <= addr < a[u] }
- X * Variant :
- X * { u - l }
- X */
- X while (upper - lower > 1) {
- X middle = (lower + upper) / 2;
- X /*
- X * m = l + (u - l) / 2 = (u + l) / 2
- X * m = l + (u - l) / 2 & u - l > 1 implies l < m < u as:
- X * m = (u + l) / 2 < (u + u) / 2 = u implies m < u
- X * m = l + (u - l) / 2 >= l + 1 implies m > l
- X */
- X if (procs[middle].addr <= addr)
- X lower = middle;
- X else
- X upper = middle;
- X printf("%5d %5d %5d\n", lower, middle, upper);
- X }
- X /*
- X * Postcondition :
- X * { a[f] <= addr < a[f + 1] } which can be expressed as:
- X * { a[l] <= addr < a[u] & u = l + 1 }
- X */
- X puts(procs[lower].name);
- X}
- X
- X/* Interact with the user testing the search algorithm */
- Xstatic void
- Xtest_search()
- X{
- X char buff[80];
- X long addr;
- X
- X puts("Enter -1 to finish");
- X do{
- X gets(buff);
- X sscanf(buff, " %lx ", &addr);
- X pr_name(addr);
- X } while (addr != -1l);
- X}
- X
- X/* Dump the procedure table */
- Xstatic void
- Xdump_table()
- X{
- X struct proc_data *pd;
- X
- X for (pd = procs ; pd < &procs[procnum] ; pd++)
- X printf("%08lx %s\n", pd->addr, pd->name);
- X}
- X#endif
- SHAR_EOF
- if test 10560 -ne "`wc -c < 'prof.c'`"
- then
- echo shar: error transmitting "'prof.c'" '(should have been 10560 characters)'
- fi
- fi # end of overwriting check
- if test -f 'profprt.c'
- then
- echo shar: will not over-write existing file "'profprt.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'profprt.c'
- X/*
- X * Print an analysis of the profiler results.
- X *
- X * (C) Copyright 1988, 1989 Diomidis D. Spinellis. All rights reserved.
- X * See the file profprt.c for distribution details.
- X *
- X * The code contained herein is not optimal. It is given as a substitute
- X * for a ten line awk script that had the same functionality.
- X *
- X * $Header: PROFPRT.C^v 1.1 88/11/20 17:36:12 dds Rel $
- X *
- X * $Log: PROFPRT.C^v $
- X * Revision 1.1 88/11/20 17:36:12 dds
- X * Initial revision
- X *
- X */
- X
- X#include <stddef.h>
- X#include <stdlib.h>
- X#include <stdio.h>
- X
- X
- X/* Profiler output maximum line length */
- X#define LINELEN 129
- X
- X/* Linker output maximum symbol length */
- X#define STRLEN 65
- X
- Xchar *Argv0 ;
- X
- Xstatic char rcsid[] = "$Header: PROFPRT.C^v 1.1 88/11/20 17:36:12 dds Rel $" ;
- X
- Xstatic void usage(void) ;
- X
- X
- Xstatic void
- Xusage()
- X{
- X fprintf(stderr, "Usage : %s [-h] [file]", Argv0);
- X exit(1);
- X}
- X
- Xvoid
- Xmain(int argc, char *argv[])
- X{
- X FILE *f;
- X long t, total = 0, max = -1;
- X static char line[LINELEN], str[STRLEN];
- X char *fname = "prof.out";
- X int histo = 0, fname_given = 0;
- X register i;
- X
- X Argv0 = argv[0];
- X
- X while (argc > 1)
- X switch (*argv[1]) {
- X case '-':
- X if (argv[1][1] == 'h') {
- X histo++;
- X argc--;
- X argv++;
- X } else
- X usage();
- X break;
- X default:
- X if (fname_given)
- X usage();
- X else {
- X fname_given++;
- X fname = argv[1];
- X argc--;
- X argv++;
- X }
- X break;
- X }
- X
- X if ((f = fopen(fname, "r")) == NULL) {
- X perror(fname);
- X exit(1);
- X }
- X for (i = 1; fgets(line, LINELEN, f); i++) {
- X if (sscanf(line, " %*s %ld ", &t) != 1) {
- X fprintf(stderr, "%s : Error in reading %s(%d)\n",
- X Argv0, fname, i);
- X exit(1);
- X }
- X total += t;
- X if (t > max)
- X max = t;
- X }
- X if (total == 0) {
- X fprintf(stderr, "%s : No hits found\n", Argv0);
- X exit(1);
- X }
- X (void) rewind(f);
- X while (fgets(line, LINELEN, f)) {
- X (void) sscanf(line, " %s %ld ", str, &t);
- X if (t) {
- X printf("%-20s %5.2lf%% ", *str == '_' ? str + 1 :
- X str, (double) t / (double) total * 100.0);
- X if (histo)
- X for (i = 0; i < (int) ((double) t /
- X (double) max * 50); i++)
- X putchar('*');
- X putchar('\n');
- X }
- X }
- X exit(0);
- X}
- SHAR_EOF
- if test 2156 -ne "`wc -c < 'profprt.c'`"
- then
- echo shar: error transmitting "'profprt.c'" '(should have been 2156 characters)'
- fi
- fi # end of overwriting check
- if test -f 'test.c'
- then
- echo shar: will not over-write existing file "'test.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'test.c'
- X/*
- X * A quick and dirty test program. Just warms up the CPU.
- X * Author: Diomidis D. Spinellis
- X */
- X
- Xvolatile int q;
- X
- X#define proc(x,n) \
- Xvoid \
- Xx()\
- X{\
- X long i;\
- X register j;\
- X for (i = 0; i < n; i++)\
- X for (j = 0; j < 15; j++)\
- X q = j;\
- X}
- X
- Xproc(a, 10000)
- Xproc(b, 4000)
- Xproc(c, 20000)
- Xproc(d, 6000)
- X
- Xvoid
- Xmain(int argc, char *argv[])
- X{
- X prof_start(argv[0]);
- X
- X a();
- X b();
- X c();
- X d();
- X a();
- X a();
- X}
- SHAR_EOF
- if test 401 -ne "`wc -c < 'test.c'`"
- then
- echo shar: error transmitting "'test.c'" '(should have been 401 characters)'
- fi
- fi # end of overwriting check
- # End of shell archive
- exit 0
-
-